#include <utility>//该头文件定义重载的关系运算符，从而达到简化关系运算符的目的，定义一个pair类型
#include <stdlib.h>//standard library标准库头文件
#include <time.h>//包含日期和时间的头文件，用于确定时间
#include "GameModel.h"

GameModel::GameModel()
{

}
void GameModel::startGame(GameType type)//开始游戏函数定义
{
    gameType = type;
    // 初始棋盘
    gameMapVec.clear();//清除游戏中棋盘和棋子的情况，从而达到初始化的目的
    for (int i = 0; i < kBoardSizeNum; i++)
    {
        std::vector<int> lineBoard;//vector的初始化，形成一个空对象
        for (int j = 0; j < kBoardSizeNum; j++)
            lineBoard.push_back(0);//压入元素，因棋局还没开始，故棋盘为空白，各点均记为0
        gameMapVec.push_back(lineBoard);//将lineBoard中的元素从gameMapVec最后开始插入，形成空白棋盘
    }

    // 如果是AI模式，需要初始化评分数组；若为双人对战模式，则不需要
    if (gameType == AI)
    {
        scoreMapVec.clear();//vector的初始化
        for (int i = 0; i < kBoardSizeNum; i++)
        {
            std::vector<int> lineScores;//初始化过程
            for (int j = 0; j < kBoardSizeNum; j++)
                lineScores.push_back(0);//元素压入
            scoreMapVec.push_back(lineScores);
        }
    }

    // 己方下为true,对方下位false，第一个下棋的为己方，故初始化为true
    playerFlag = true;
}

void GameModel::updateGameMap(int row, int col)//每次落子后进行期盼的更新体现棋局的进程
{
    if (playerFlag)//如果是己方落子，则下白子，落子将该点的数据改为1
        gameMapVec[row][col] = 1;
    else
        gameMapVec[row][col] = -1;//若为对方落子，即下黑子，落子将该点数据改为-1

    // 换手
    playerFlag = !playerFlag;//一次落子之后则下棋方改变，换为对方
}

void GameModel::actionByPerson(int row, int col)//人执行下棋的行为
{
    updateGameMap(row, col);
}

void GameModel::actionByAI(int &clickRow, int &clickCol)//机器执行下棋行为
{
    // 计算评分
    calculateScore();

    // 从评分中找出最大分数的位置
    int maxScore = 0;
    std::vector<std::pair<int, int>> maxPoints;//对插入元素不进行自动排序，且允许重复

    for (int row = 1; row < kBoardSizeNum; row++)
        for (int col = 1; col < kBoardSizeNum; col++)
        {
            // 前提是这个坐标是空的
            if (gameMapVec[row][col] == 0)
            {
                if (scoreMapVec[row][col] > maxScore)          // 找最大的数和坐标
                {
                    maxPoints.clear();//清除原最大数的数据，后续加入新的最大值
                    maxScore = scoreMapVec[row][col];
                    maxPoints.push_back(std::make_pair(row, col));
                }
                else if (scoreMapVec[row][col] == maxScore)     // 如果有多个最大的数，都存起来
                    maxPoints.push_back(std::make_pair(row, col));
            }
        }

    // 随机落子，如果有多个点的话
    srand((unsigned)time(0));
    int index = rand() % maxPoints.size();//生成0到maxPoints.size()-1之间随机数字

    std::pair<int, int> pointPair = maxPoints.at(index);
    clickRow = pointPair.first; // 记录落子点
    clickCol = pointPair.second;
    updateGameMap(clickRow, clickCol);//AI落子后更新棋盘，并实现换手
}
void GameModel::calculateScore()
{
    // 统计玩家或者电脑连成的子
    int personNum = 0; // 玩家连成子的个数
    int botNum = 0; // AI连成子的个数
    int emptyNum = 0; // 各方向空白位的个数

    // 清空评分数组
    scoreMapVec.clear();
    for (int i = 0; i < kBoardSizeNum; i++)
    {
        std::vector<int> lineScores;
        for (int j = 0; j < kBoardSizeNum; j++)
            lineScores.push_back(0);
        scoreMapVec.push_back(lineScores);
    }

    // 计分（此处是完全遍历）
    for (int row = 0; row < kBoardSizeNum; row++)
        for (int col = 0; col < kBoardSizeNum; col++)
        {
            // 空白点就算
            if (row > 0 && col > 0 &&
                gameMapVec[row][col] == 0)
            {
                // 遍历周围八个方向（八个方向为田字除去中心点的其他八个点），接下来的for循环为确定方向
                for (int y = -1; y <= 1; y++)
                    for (int x = -1; x <= 1; x++)
                    {
                        // 重置
                        personNum = 0;
                        botNum = 0;
                        emptyNum = 0;

                        // 原坐标不算
                        if (!(y == 0 && x == 0))
                        {
                            // 每个方向延伸4个子，即确定是否连成四个点，方向由x，y确定

                            // 对玩家白子评分（正反两个方向）
                            for (int i = 1; i <= 4; i++)//正向
                            {
                                if (row + i * y > 0 && row + i * y < kBoardSizeNum &&
                                    col + i * x > 0 && col + i * x < kBoardSizeNum &&
                                    gameMapVec[row + i * y][col + i * x] == 1) // 玩家的子，白子，且确定该子在棋盘内
                                {
                                    personNum++;
                                }
                                else if (row + i * y > 0 && row + i * y < kBoardSizeNum &&
                                         col + i * x > 0 && col + i * x < kBoardSizeNum &&
                                         gameMapVec[row + i * y][col + i * x] == 0) // 空白位
                                {
                                    emptyNum++;
                                    break;
                                }
                                else            // 出边界或遇到黑子
                                    break;
                            }

                            for (int i = 1; i <= 4; i++)//反向，与正向思路相同
                            {
                                if (row - i * y > 0 && row - i * y < kBoardSizeNum &&
                                    col - i * x > 0 && col - i * x < kBoardSizeNum &&
                                    gameMapVec[row - i * y][col - i * x] == 1) // 玩家的子
                                {
                                    personNum++;
                                }
                                else if (row - i * y > 0 && row - i * y < kBoardSizeNum &&
                                         col - i * x > 0 && col - i * x < kBoardSizeNum &&
                                         gameMapVec[row - i * y][col - i * x] == 0) // 空白位
                                {
                                    emptyNum++;
                                    break;
                                }
                                else            // 出边界或遇到黑子
                                    break;
                            }

                            if (personNum == 1)                      // 杀二，玩家白子连成1个点
                                scoreMapVec[row][col] += 10;
                            else if (personNum == 2)                 // 杀三
                            {
                                if (emptyNum == 1)//在其中一个端点处有空点，另一端为黑子
                                    scoreMapVec[row][col] += 30;
                                else if (emptyNum == 2)//两端均为空点
                                    scoreMapVec[row][col] += 40;
                            }
                            else if (personNum == 3)                 // 杀四，若将空点补上白子则玩家连成四个点
                            {
                                // 量变空位不一样，优先级不一样
                                if (emptyNum == 1)//一端为黑子，另一端为空点
                                    scoreMapVec[row][col] += 60;
                                else if (emptyNum == 2)//两端都为空点
                                    scoreMapVec[row][col] += 110;
                            }
                            else if (personNum == 4)                 // 杀五，将空点补成白子连成五个点
                                scoreMapVec[row][col] += 10100;

                            // 进行一次清空
                            emptyNum = 0;


                            // 对AI/黑子评分
                            for (int i = 1; i <= 4; i++)
                            {
                                if (row + i * y > 0 && row + i * y < kBoardSizeNum &&
                                    col + i * x > 0 && col + i * x < kBoardSizeNum &&
                                    gameMapVec[row + i * y][col + i * x] == -1) // AI的子
                                {
                                    botNum++;
                                }
                                else if (row + i * y > 0 && row + i * y < kBoardSizeNum &&
                                         col + i * x > 0 && col + i * x < kBoardSizeNum &&
                                         gameMapVec[row +i * y][col + i * x] == 0) // 空白位
                                {
                                    emptyNum++;
                                    break;
                                }
                                else            // 出边界或遇到白子
                                    break;
                            }

                            for (int i = 1; i <= 4; i++)
                            {
                                if (row - i * y > 0 && row - i * y < kBoardSizeNum &&
                                    col - i * x > 0 && col - i * x < kBoardSizeNum &&
                                    gameMapVec[row - i * y][col - i * x] == -1) // AI的子
                                {
                                    botNum++;
                                }
                                else if (row - i * y > 0 && row - i * y < kBoardSizeNum &&
                                         col - i * x > 0 && col - i * x < kBoardSizeNum &&
                                         gameMapVec[row - i * y][col - i * x] == 0) // 空白位
                                {
                                    emptyNum++;
                                    break;
                                }
                                else            // 出边界或遇到白子
                                    break;
                            }

                            if (botNum == 0)                      // 普通下子
                                scoreMapVec[row][col] += 5;
                            else if (botNum == 1)                 // 活二
                                scoreMapVec[row][col] += 10;
                            else if (botNum == 2)
                            {
                                if (emptyNum == 1)                // 死三，该点下成黑子后，连成三个点，但一侧是边界或者对方白子，一侧为空点
                                    scoreMapVec[row][col] += 25;
                                else if (emptyNum == 2)
                                    scoreMapVec[row][col] += 50;  // 活三，该点下成黑子后，连成三个点，两侧均为空点
                            }
                            else if (botNum == 3)
                            {
                                if (emptyNum == 1)                // 死四
                                    scoreMapVec[row][col] += 55;
                                else if (emptyNum == 2)
                                    scoreMapVec[row][col] += 100; // 活四，两端均为空点
                            }
                            else if (botNum >= 4)
                                scoreMapVec[row][col] += 10000;   // 活五

                        }
                    }

            }
        }
}
bool GameModel::Win(int row, int col)//判断是否获胜
{
    // 横竖斜四种大情况，每种情况都根据当前落子往后遍历5个棋子，有一种符合就算赢
    // 水平方向
    for (int i = 0; i < 5; i++)
    {
        // 往左5个，往右匹配4个子，20种情况
        if (col - i > 0 &&
            col - i + 4 < kBoardSizeNum &&
            gameMapVec[row][col - i] == gameMapVec[row][col - i + 1] &&
            gameMapVec[row][col - i] == gameMapVec[row][col - i + 2] &&
            gameMapVec[row][col - i] == gameMapVec[row][col - i + 3] &&
            gameMapVec[row][col - i] == gameMapVec[row][col - i + 4])//前两个条件确保不越界，后四个条件确保棋子颜色相同
            return true;
    }

    // 竖直方向(上下延伸4个)
    for (int i = 0; i < 5; i++)
    {
        if (row - i > 0 &&
            row - i + 4 < kBoardSizeNum &&
            gameMapVec[row - i][col] == gameMapVec[row - i + 1][col] &&
            gameMapVec[row - i][col] == gameMapVec[row - i + 2][col] &&
            gameMapVec[row - i][col] == gameMapVec[row - i + 3][col] &&
            gameMapVec[row - i][col] == gameMapVec[row - i + 4][col])
            return true;
    }

    // 左斜方向
    for (int i = 0; i < 5; i++)
    {
        if (row + i < kBoardSizeNum &&
            row + i - 4 > 0 &&
            col - i > 0 &&
            col - i + 4 < kBoardSizeNum &&
            gameMapVec[row + i][col - i] == gameMapVec[row + i - 1][col - i + 1] &&
            gameMapVec[row + i][col - i] == gameMapVec[row + i - 2][col - i + 2] &&
            gameMapVec[row + i][col - i] == gameMapVec[row + i - 3][col - i + 3] &&
            gameMapVec[row + i][col - i] == gameMapVec[row + i - 4][col - i + 4])
            return true;
    }

    // 右斜方向
    for (int i = 0; i < 5; i++)
    {
        if (row - i > 0 &&
            row - i + 4 < kBoardSizeNum &&
            col - i > 0 &&
            col - i + 4 < kBoardSizeNum &&
            gameMapVec[row - i][col - i] == gameMapVec[row - i + 1][col - i + 1] &&
            gameMapVec[row - i][col - i] == gameMapVec[row - i + 2][col - i + 2] &&
            gameMapVec[row - i][col - i] == gameMapVec[row - i + 3][col - i + 3] &&
            gameMapVec[row - i][col - i] == gameMapVec[row - i + 4][col - i + 4])
            return true;
    }

    return false;
}

bool GameModel::DeadGame()//判断是否死局，故和棋
{
    // 所有空格全部填满
    for (int i = 1; i < kBoardSizeNum; i++)
        for (int j = 1; j < kBoardSizeNum; j++)
        {
            if (!(gameMapVec[i][j] == 1 || gameMapVec[i][j] == -1))
                return false;
        }
    return true;
}


